package org.dromara.system.service.impl;

import cn.hutool.core.bean.BeanUtil;
import lombok.extern.slf4j.Slf4j;
import cn.hutool.core.collection.CollUtil;
import org.dromara.common.core.exception.BusiException;
import org.dromara.common.core.utils.S;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.core.utils.MapstructUtils;
import org.dromara.common.mybatis.binding.Binder;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.mybatis.core.page.PageQuery;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.RequiredArgsConstructor;
import org.dromara.common.mybatis.utils.BeanUtils;
import org.dromara.common.mybatis.utils.V;
import org.dromara.system.domain.bo.SysConfigBo;
import org.dromara.system.domain.vo.SysConfigVo;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.stereotype.Service;
import org.dromara.system.domain.bo.SysI18nConfigBo;
import org.dromara.system.domain.vo.SysI18nConfigVo;
import org.dromara.system.domain.SysI18nConfig;
import org.dromara.system.mapper.SysI18nConfigMapper;
import org.dromara.system.service.ISysI18nConfigService;
import org.springframework.transaction.annotation.Transactional;
import org.dromara.common.mybatis.service.impl.ServiceImpl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 国际化配置Service业务层处理
 *
 * @author yilong.fu
 * @date 2024-11-06
 */
@RequiredArgsConstructor
@Service
@Slf4j
public class SysI18nConfigServiceImpl extends ServiceImpl<SysI18nConfigMapper, SysI18nConfig, SysI18nConfigBo, SysI18nConfigVo> implements ISysI18nConfigService {


    public SysI18nConfigVo fill(SysI18nConfigVo entity) {
        SysI18nConfigVo vo = Binder.convertAndBindRelations(entity, SysI18nConfigVo.class);
        return vo;
    }

    @Override
    public LambdaQueryWrapper<SysI18nConfig> buildQueryWrapper(LambdaQueryWrapper<SysI18nConfig> lqw, SysI18nConfigBo bo) {
        lqw.eq(StringUtils.isNotBlank(bo.getType()), SysI18nConfig::getType, bo.getType());
        lqw.eq(StringUtils.isNotBlank(bo.getLanguage()), SysI18nConfig::getLanguage, bo.getLanguage());
        lqw.likeRight(StringUtils.isNotBlank(bo.getEnCode()), SysI18nConfig::getEnCode, bo.getEnCode());
        lqw.like(StringUtils.isNotBlank(bo.getContent()), SysI18nConfig::getContent, bo.getContent());
        lqw.eq(bo.getSeq() != null, SysI18nConfig::getSeq, bo.getSeq());
        return lqw;
    }


    /**
     * 更新前的数据校验
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean validEntityBeforeUpdate(SysI18nConfig entity) {
        //TODO 做一些数据校验,如唯一约束
        return true;
    }

    /**
     * 保存前的数据校验
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean validEntityBeforeSave(SysI18nConfig entity) {

        return true;
    }


    /**
     * 新增红包
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean insertOrUpdateByBo(SysI18nConfigBo bo) {
        SysI18nConfig add = MapstructUtils.convert(bo, getEntityClass());
        boolean flag = validEntityBeforeSave(add);
        if (!flag) {
            return flag;
        }

        SysI18nConfigVo exist = getOne(new SysI18nConfigBo().builder().language(add.getLanguage())
            .type(add.getType())
            .enCode(add.getEnCode()).build());
        if (exist == null) {
            flag = baseMapper.insert(add) > 0;
            if (flag) {
                BeanUtil.setProperty(bo, "id", BeanUtil.getProperty(add, "id"));
            }
        } else {
            SysI18nConfig update = MapstructUtils.convert(exist, getEntityClass());
            update.setContent(add.getContent());
            baseMapper.updateById(update);
        }
        return flag;
    }

    @Override
    public List<SysI18nConfigVo> importList(List<SysI18nConfigVo> datas, Integer mode, boolean updatePart) {
        if (CollUtil.isEmpty(datas)) {
            throw new BusiException("导入数据不能为空");
        }
        List<SysI18nConfigVo> errorList = new ArrayList<>();
        datas.forEach(item -> {
            SysI18nConfigBo bo = new SysI18nConfigBo();
            BeanUtil.copyProperties(item, bo);
            if (mode == 1) {   //新增和修改
                insertOrUpdateByBo(bo);
            } else if (mode == 2) {
                if (bo.getId() != null) {
                    SysI18nConfigVo exists = queryById(bo.getId());
                    if (exists != null) {
                    } else {
                        insertOrUpdateByBo(bo);
                    }
                } else {
                    insertOrUpdateByBo(bo);
                }
            } else {
                if (bo.getId() != null) {
                    SysI18nConfigVo exists = queryById(bo.getId());
                    if (exists != null) {
                        bo.setId(exists.getId());
                        updateByBo(bo);
                    }
                }
            }
        });
        return errorList;
    }


    @Override
    public void bindI18nContent(List<?> voList, String getI18nType, String getI18nCodeField, String setI18nContentField) {
        if (!V.notEmpty(voList)) {
            return;
        }
        Locale locale = LocaleContextHolder.getLocale();
        String language = locale.toString();
        // 获取当前语言的缓存数据
//        Map<String, String> languageCached = i18nCacheManager.getLanguageCached(language);
        Set<String> codes = new HashSet<>();
        for (Object item : voList) {
            Object i18nCode = BeanUtils.getProperty(item, getI18nCodeField);
            if (V.notEmpty(i18nCode)) {
                codes.add(S.valueOf(i18nCode));
            }
        }
//        for (Object item : voList) {
//            Object i18nCode = BeanUtils.getProperty(item, getI18nCodeField);
//            // 缓存中已经存在的数据直接赋值，不存在的进行数据库查询
//            if (V.notEmpty(i18nCode)) {
//                if (V.notEmpty(languageCached) && V.notEmpty(languageCached.get(i18nCode))) {
//                    BeanUtils.setProperty(item, setI18nContentField, languageCached.get(i18nCode));
//                    log.trace("语言环境 {} 从缓存中获取 {} 的选项数据", language, i18nCode);
//                } else {
//                    codes.add(S.valueOf(i18nCode));
//                }
//            }
//        }
//        if (V.isEmpty(codes)) {
//            return;
//        }
        LambdaQueryWrapper<SysI18nConfig> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.select(SysI18nConfig::getLanguage, SysI18nConfig::getEnCode, SysI18nConfig::getContent);
        queryWrapper.in(SysI18nConfig::getEnCode, codes);
        queryWrapper.in(SysI18nConfig::getType, getI18nType);
        queryWrapper.eq(SysI18nConfig::getLanguage, language);
        List<SysI18nConfigVo> i18nConfigList = queryList(queryWrapper);
        if (V.isEmpty(i18nConfigList)) {
            log.warn("未获取到国际化翻译 {}: {}，请检查国际化翻译配置", language, codes);
            return;
        }

        Map<String, String> i18nMap = new HashMap<>();
        for (SysI18nConfigVo item : i18nConfigList) {
            i18nMap.put(item.getEnCode(), item.getContent());
        }
        // 将查询的数据缓存
//        i18nCacheManager.cacheLanguage(language, i18nMap);
        // 将剩下的国际化数据进行赋值
        for (Object item : voList) {
            Object i18nCode = BeanUtils.getProperty(item, getI18nCodeField);
            if (V.notEmpty(i18nCode)) {
                if (!codes.contains(S.valueOf(i18nCode))) {
                    continue;
                }
                String content = i18nMap.get(S.valueOf(i18nCode));
                if (V.notEmpty(content)) {
                    BeanUtils.setProperty(item, setI18nContentField, content);
                }
            }
        }
    }

    @Override
    public Map<String, String> translate(List<String> i18nKeys) {
        return Map.of();
    }
}
